package com.hencoder.scalableimageview.view

import android.animation.ObjectAnimator
import android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.util.AttributeSet
import android.view.GestureDetector
import android.view.MotionEvent
import android.view.ScaleGestureDetector
import android.view.View
import android.widget.OverScroller
import android.widget.Scroller
import androidx.core.animation.doOnEnd
import androidx.core.view.GestureDetectorCompat
import androidx.core.view.ViewCompat
import com.example.scalableview.R
import com.hencoder.scalableimageview.dp
import com.hencoder.scalableimageview.getBitmap
import kotlin.math.max
import kotlin.math.min

//为了实现上下也能滑动，所以再扩大一点
private const val EXTRA_SCALE_FACTOR = 1.5f
private val IMAGE_SIZE = 300.dp.toInt()

class ScalableImageView(context: Context?, attrs: AttributeSet?) : View(context, attrs),
  GestureDetector.OnGestureListener, Runnable {
  private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
  private val bitmap = getBitmap(resources, IMAGE_SIZE)
  private var offsetX = 0f
  private var offsetY = 0f
  //大图模式下移动时的偏移量
  private var extraOffsetX = 0f
  private var extraOffsetY = 0f
  private var smallScale = 0f
  private var bigScale = 0f

  //双击后改变这个变量来放大
  private var big = false

  //放大缩小比例
  private var scaleFraction = 0f
  set(value) {
    field = value
    invalidate()
  }

  private var currentScale = 0f
    set(value) {
      field = value
      invalidate()
    }

  //双指缩放
  private val scaleGestureDetector = ScaleGestureDetector(context,object : ScaleGestureDetector.OnScaleGestureListener{
    override fun onScale(detector: ScaleGestureDetector): Boolean {
      val tempCurrentScale = currentScale * detector.scaleFactor
      if (tempCurrentScale < smallScale || tempCurrentScale > bigScale){
        return false
      }else{
        currentScale *= detector.scaleFactor
        return true
      }

      // 这个返回值表示「事件是否消耗」，即「这个事件算不算数」
      //return true 则scaleFactor表示当前状态放缩系数和前一个状态的比值
      //return false则scaleFactor表示当前状态放缩系数和初始状态的比值
      return true
    }

    override fun onScaleBegin(detector: ScaleGestureDetector): Boolean {
      //实现放大移动后缩小恢复到原位置
      extraOffsetX = (1- bigScale / smallScale) * (detector.focusX - width / 2)
      extraOffsetY = (1- bigScale / smallScale) * (detector.focusY - height / 2)
      return true
    }

    override fun onScaleEnd(detector: ScaleGestureDetector?) {

    }

  })

  //放大缩小动画
  private val scaleAnimator: ObjectAnimator by lazy {
    ObjectAnimator.ofFloat(this,"currentScale",smallScale,bigScale)

  }
  private val gestureDetector = GestureDetectorCompat(context,this).apply {
    setOnDoubleTapListener(object :GestureDetector.OnDoubleTapListener{
      override fun onSingleTapConfirmed(e: MotionEvent?): Boolean {
        return false
      }

      override fun onDoubleTap(e: MotionEvent): Boolean {
        big = !big
        if (big){

          //实现放大移动后缩小恢复到原位置
          extraOffsetX = (1- bigScale / smallScale) * (e.x - width / 2)
          extraOffsetY = (1- bigScale / smallScale) * (e.y - height / 2)

          extraOffsetX = min(extraOffsetX,(bitmap.width * bigScale - width)/2)
          extraOffsetX = max(extraOffsetX,- (bitmap.width * bigScale - width)/2)
          extraOffsetY = min(extraOffsetY,(bitmap.height * bigScale - height)/2)
          extraOffsetY = max(extraOffsetY,- (bitmap.height * bigScale - height)/2)

          scaleAnimator.start()
        }else{
          scaleAnimator.reverse()
        }

        return true
      }

      override fun onDoubleTapEvent(e: MotionEvent?): Boolean {
        return false
      }
    })
  }

  //计算滑动偏移，用于实现惯性滑动
  private val overScroller = OverScroller(context)

  override fun onTouchEvent(event: MotionEvent?): Boolean {
    scaleGestureDetector.onTouchEvent(event)
    if (!scaleGestureDetector.isInProgress){
      gestureDetector.onTouchEvent(event)
    }
    return true
  }

  override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
    offsetX = ((width - IMAGE_SIZE) / 2).toFloat()
    offsetY = ((height - IMAGE_SIZE) / 2).toFloat()

    //实现图片放大逻辑
    if ((bitmap.width / bitmap.height).toFloat() > (width / height).toFloat()){
      //这个bitmap是方图,smallScale应该以view的宽为基准
      smallScale = width / bitmap.width.toFloat()
      bigScale = height / bitmap.height.toFloat() * EXTRA_SCALE_FACTOR
    }else{
      smallScale = height / bitmap.height.toFloat()
      bigScale = width / bitmap.width.toFloat() * EXTRA_SCALE_FACTOR
    }
    currentScale = smallScale
    scaleAnimator.setFloatValues(smallScale,bigScale)
  }

  override fun onDraw(canvas: Canvas) {

    var scaleFraction = (currentScale - smallScale) / (bigScale - smallScale)
    //移动
    canvas.translate(extraOffsetX * scaleFraction,extraOffsetY * scaleFraction)

    //放大

    canvas.scale(currentScale,currentScale, (width/2).toFloat(), (height/2).toFloat())
    canvas.drawBitmap(bitmap,offsetX,offsetY,paint)

  }

  override fun onDown(e: MotionEvent?): Boolean {
    return true
  }

  override fun onShowPress(e: MotionEvent?) {

  }

  override fun onSingleTapUp(e: MotionEvent?): Boolean {
    return false
  }

  override fun onScroll(
    e1: MotionEvent?,
    e2: MotionEvent?,
    distanceX: Float,
    distanceY: Float
  ): Boolean {
    if (big){
      extraOffsetX -= distanceX
      //修正偏移，保证只能在图片大小内滑动
      extraOffsetX = min(extraOffsetX,(bitmap.width * bigScale - width)/2)
      extraOffsetX = max(extraOffsetX,- (bitmap.width * bigScale - width)/2)
      extraOffsetY -= distanceY
      extraOffsetY = min(extraOffsetY,(bitmap.height * bigScale - height)/2)
      extraOffsetY = max(extraOffsetY,- (bitmap.height * bigScale - height)/2)
      invalidate()
    }
    return false
  }

  override fun onLongPress(e: MotionEvent?) {

  }

  override fun onFling(
    e1: MotionEvent?,
    e2: MotionEvent?,
    velocityX: Float,
    velocityY: Float
  ): Boolean {
    if (big){
      overScroller.fling(extraOffsetX.toInt(), extraOffsetY.toInt(), velocityX.toInt(), velocityY.toInt(),
              (- (bitmap.width * bigScale - width) / 2).toInt(),
              ((bitmap.width * bigScale - width) / 2).toInt(),
              (- (bitmap.height * bigScale - height) / 2).toInt(),
              ((bitmap.height * bigScale - height) / 2).toInt(),
              40.dp.toInt(), 40.dp.toInt())

      //下一帧到来时执行Runnable
      ViewCompat.postOnAnimation(this,this)
    }

    return false
  }

  override fun run() {
    //计算当前的位置，返回值是惯性运动是否还在进行
    if(overScroller.computeScrollOffset()){
      //取当前位置
      extraOffsetX = overScroller.currX.toFloat()
      extraOffsetY = overScroller.currY.toFloat()
      invalidate()
      ViewCompat.postOnAnimation(this,this)
    }
  }





}